package cn.funeralobjects.aoss.web.controller;

import cn.funeralobjects.aoss.entity.EBucket;
import cn.funeralobjects.aoss.enums.BucketAction;
import cn.funeralobjects.aoss.service.BucketService;
import cn.funeralobjects.aoss.web.api.BucketApi;
import cn.funeralobjects.aoss.web.mapper.BucketActionPropertyEditor;
import cn.funeralobjects.aoss.web.mapper.BucketMapper;
import cn.funeralobjects.aoss.web.model.VBucket;
import cn.funeralobjects.aoss.web.model.VBucketStsAccessKey;
import cn.funeralobjects.common.service.CodeService;
import cn.funeralobjects.common.service.IdService;
import cn.funeralobjects.common.web.controller.RestCodeController;
import cn.funeralobjects.common.web.controller.converter.VoMapper;
import cn.funeralobjects.util.ReactorUtils;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.SimplifiedObjectMeta;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;
import java.util.List;

/**
 * Controller of Bucket implements By BucketApi
 *
 * @author FuneralObjects
 * Create date: 2020/6/1 3:00 PM
 */
@RestController
@RequestMapping("/bucket")
public class BucketController implements BucketApi, RestCodeController<VBucket, EBucket, Integer> {

    @Resource
    public BucketService bucketService;

    @Resource
    private BucketMapper bucketMapper;

    @PutMapping("/prod-res-code-{prodResCode}/buckets")
    @Override
    public Mono<List<VBucket>> syncBucket(@PathVariable String prodResCode) {
        return bucketService.syncFromCloudByProductRes(prodResCode).map(bucketMapper::toVo);
    }

    @GetMapping("/{id}/name")
    @Override
    public Mono<String> getBucketName(@PathVariable Integer id) {
        return Mono.just(id).map(bucketService::getNameById).flatMap(ReactorUtils::getOrEmpty);
    }

    @PutMapping("/{id}/ram-role")
    @Override
    public Mono<Void> bindRamRole(@PathVariable Integer id, @RequestParam("ram-role-code") String ramRoleCode) {
        return Mono.defer(() -> {
            bucketService.bindRamRole(id, ramRoleCode);
            return Mono.empty();
        });
    }

    @PostMapping("/{id}/sts")
    @Override
    public Mono<VBucketStsAccessKey> createStsAccess(@PathVariable Integer id,
                                                     @RequestParam("sts-prod-res-id") Integer stsProdResId,
                                                     @RequestParam("action") BucketAction action,
                                                     @RequestParam("path") String path,
                                                     @RequestParam(value = "duration", required = false) Long duration) {
        return Mono.defer(() -> Mono.just(bucketService.createStsAccessKey(id, stsProdResId, action, path, duration)).map(bucketMapper::toVo));
    }

    @GetMapping("/{id}/object/simplified-meta")
    @Override
    public Mono<SimplifiedObjectMeta> getSimplifiedObjectMeta(@PathVariable Integer id,
                                                              @RequestParam("object-path") String objectPath) {
        return Mono.defer(() -> {
            String path = objectPath.startsWith("/") ? objectPath.substring(1) : objectPath;
            return Mono.just(bucketService.getSimplifiedObjectMeta(id, path));
        });
    }

    @GetMapping("/{id}/object/head-meta")
    @Override
    public Mono<ObjectMetadata> headObjectMeta(@PathVariable Integer id, @RequestParam("object-path") String objectPath) {
        return Mono.defer(() -> {
            String path = objectPath.startsWith("/") ? objectPath.substring(1) : objectPath;
            return Mono.just(bucketService.headObjectMeta(id, path));
        });
    }

    @InitBinder
    private void initBind(WebDataBinder dataBinder) {
        dataBinder.registerCustomEditor(BucketAction.class, new BucketActionPropertyEditor());
    }

    @Override
    public CodeService<EBucket, Integer> codeService() {
        return bucketService;
    }

    @Override
    public IdService<Integer> idService() {
        return bucketService;
    }

    @Override
    public VoMapper<EBucket, VBucket> voMapper() {
        return bucketMapper;
    }
}
